﻿/****************************** Module Header ******************************\
 * Module Name:  mxForm.cs
 * Module Version:  1.0.0 (2012-8-16)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to extension Form instance's method.  It supplies 
 * public static extension methods to load data or get othor control.
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Drawing;

namespace UCL.Forms
{
    public static class mxForm
    {
        /// <summary>
        /// 打开MIDI窗体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static T OpenMidiForm<T>(this Form frm, Func<T> act = null, bool refresh = false) where T : Form, new()
        {
            foreach (Form f in frm.MdiChildren)
            {
                if (f.GetType() == typeof(T))
                {
                    if (refresh)
                    {
                        f.Close();
                    }
                    else
                    {
                        f.Activate();
                        return (T)f;
                    }
                }
            }
            T mdifrm = act == null ? new T() : act();
            if (mdifrm.IsDisposed) return null;
            mdifrm.MdiParent = frm;
            mdifrm.Dock = DockStyle.Fill;
            mdifrm.Show();
            return mdifrm;
        }

        /// <summary>
        /// 在TabControl中打开Mdi子窗体
        /// <para>2012-9-8</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="frm"></param>
        /// <param name="act"></param>
        /// <returns></returns>
        public static T OpenMdiTabForm<T>(this Form frm, Func<T> act = null) where T : Form, new()
        {
            /*
            foreach (Form f in frm.MdiChildren)
            {
                if (f.GetType() == typeof(T))
                {
                    f.Activate();
                    return (T)f;
                }
            }
             */
            TabControl tc = (TabControl)frm.Controls[0];
            foreach (TabPage tpTemp in tc.TabPages)
            {
                if (tpTemp.Tag != null && tpTemp.Tag.GetType() == typeof(T))
                {
                    tc.SelectTab(tpTemp);
                    return (T)tpTemp.Tag;
                }
            }
            T mdifrm = act == null ? new T() : act();
            mdifrm.TopLevel = false;
            mdifrm.Dock = DockStyle.Fill;
            TabPage tp = new TabPage(mdifrm.Text);
            tp.Parent = tc;
            tp.Tag = mdifrm;
            tp.Show();
            tp.Controls.Add(mdifrm);
            mdifrm.Show();
            tc.SelectedTab = tp;
            return mdifrm;
        }

        /// <summary>
        /// 打开普通窗体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        /// <param name="act"></param>
        public static void OpenForm<T>(this Form f, Func<T> act = null, bool isChild = false, bool setOwner = true) where T : Form, new()
        {
            T t = act == null ? new T() : act();
            if (setOwner) t.Owner = f;
            t.StartPosition = FormStartPosition.CenterScreen;
            t.FormBorderStyle = FormBorderStyle.Sizable;
            if (isChild)
            {
                t.Show(f);
            }
            else
            {
                t.Show();
            }
        }

        /// <summary>
        /// 获取指定程序集中指定名称的类型
        /// <para>如：this.OpenFormByType("MSeatClient.Customer","MSeatClient.Customer.frmCustomerEdit", new Dictionary&lt;string, object&gt; { { "PrimaryID", dgvList.GetCurrentValue("colHidBuyerUserID_").ToString().ToGuid() } });</para>
        /// </summary>
        /// <param name="f"></param>
        /// <param name="assemblyname"></param>
        /// <param name="formname"></param>
        /// <remarks>2013-10-4 by sutroon</remarks>
        public static void OpenFormByType(this Form f, string assemblyname, string formname, Dictionary<string, object> properties = null)
        {
            Type type = f.GetFormByType(assemblyname, formname);
            object frm = Activator.CreateInstance(type);
            List<string> msg = new List<string>();
            if (properties != null)
            {
                foreach (string n in properties.Keys)
                {
                    PropertyInfo pi = type.GetProperty(n);
                    if (pi == null)
                    {
                        msg.Add("成员 [{0}] null".Fmt(n));
                    }
                    else
                    {
                        pi.SetValue(frm, properties[n], null);
                    }
                }
            }
            if (msg.Count > 0) MessageBox.Show(msg.ToString(Environment.NewLine));
            ((Form)frm).Show();
        }

        /// <summary>
        /// 获取指定程序集中指定名称的类型
        /// </summary>
        /// <param name="f"></param>
        /// <param name="assemblyname"></param>
        /// <param name="formname"></param>
        /// <returns></returns>
        /// <remarks>2013-10-4 by sutroon</remarks>
        public static Type GetFormByType(this Form f, string assemblyname, string formname)
        {
            if (!formname.Contains('.')) formname = assemblyname + "." + formname;
            Assembly ass = Assembly.Load(assemblyname);
            Type type = ass.GetType(formname);
            return type;
        }

        /// <summary>
        /// 打开子窗体对话框
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        public static void OpenDialog<T>(this Form f, Func<T> act = null) where T : Form, new()
        {
            T t = act == null ? new T() : act();
            t.Owner = f;
            t.StartPosition = FormStartPosition.CenterScreen;
            t.ShowInTaskbar = true;
            t.Show();
        }

        /// <summary>
        /// 2013-8-5 by sutroon
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        public static void ShowFormAsChild<T>(this Form f) where T : Form, new()
        {
            if (f.Parent == null)
            {
                new T().Show();
                return;
            }

            bool existsForm = false;
            foreach (Control c in f.Parent.Controls)
            {
                if (c.GetType() == typeof(T))
                {
                    existsForm = true;
                    c.BringToFront();
                    break;
                }
            }
            if (!existsForm)
            {
                T frm = new T() { TopLevel = false, Parent = f.Parent, Dock = DockStyle.Fill };
                f.Parent.Controls.Add(frm);
                frm.Show();
                frm.BringToFront();
            }

        }

        /// <summary>
        /// 刷新父窗体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        /// <param name="methodname"></param>
        public static void RefreshOwner<T>(this Form f, string methodname = "FormLoad", params object[] args) where T : Form
        {
            if (f.Owner == null || f.Owner.GetType() != typeof(T)) return;
            T owner = (T)f.Owner;
            owner.BringToFront(); // 2014-5-16
            owner.GetType().InvokeMember(methodname, BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, owner, args);
        }

        /// <summary>
        /// 刷新指定程序集中指定名称的父窗体
        /// </summary>
        /// <param name="f"></param>
        /// <param name="assemblyname"></param>
        /// <param name="formname"></param>
        /// <param name="methodname"></param>
        /// <param name="args"></param>
        /// <remarks>2013-10-4 by sutroon</remarks>
        public static void RefreshOwnerByType(this Form f, string assemblyname, string formname, string methodname = "FormLoad", params object[] args)
        {
            if (f.Owner == null) return;
            Type type = f.GetFormByType(assemblyname, formname);
            if (f.Owner.GetType() != type) return;
            f.Owner.GetType().InvokeMember(methodname, BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, f.Owner, args);
        }

        /// <summary>
        /// 刷新父控件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        /// <param name="methodname"></param>
        public static void RefreshTag(this Form f, string methodname = "FormLoad", params object[] args)
        {
            if (f.Tag == null) return;
            f.Tag.GetType().InvokeMember(methodname, BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, f.Tag, args);
        }

        /// <summary>
        /// 递归父窗体获取Mdi窗体
        /// <para>this.FindMdiForm&lt;frmHome&gt;();</para>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T FindMdiForm<T>(this Form f, string name = "") where T : Form
        {
            if (name.Length == 0) name = typeof(T).Name;
            return f.FindMdiFormFunc<T>(name);
        }
        public static T FindMdiFormFunc<T>(this Form f, string name) where T : Form
        {
            if (f.MdiParent != null)
            {
                foreach (Form c in f.MdiParent.MdiChildren)
                {
                    if (c.Name == name && c.GetType() == typeof(T)) return (T)c;
                }
            }
            return f.Owner == null ? null : f.Owner.FindMdiFormFunc<T>(name);
        }

        /// <summary>
        /// 调用任意页面的方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="f"></param>
        /// <param name="methodname"></param>
        /// <param name="args"></param>
        public static void CallFunc<T>(this Form f, string methodname, params object[] args) where T : Form, new()
        {
            T t = new T();
            typeof(T).InvokeMember(methodname, BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, t, args);
        }

        #region 移动窗体方法1

        // 窗体是否移动
        private static bool bolBeginDrag;

        // 鼠标坐标
        private static int intLeft, intTop;

        /// <summary>
        /// 通过控件移动窗体(用于无边框窗体)
        /// </summary>
        /// <param name="frm"></param>
        /// <param name="c"></param>
        public static void MoveByControl(this Form frm, Control c, double opacity = 0.8)
        {
            c.MouseDown += (object s, MouseEventArgs e) =>
            {
                frm.Opacity = opacity;
                bolBeginDrag = true;
                intLeft = e.X;
                intTop = e.Y;
            };
            c.MouseUp += (object s, MouseEventArgs e) =>
            {
                frm.Opacity = 1;
                if (bolBeginDrag)
                {
                    frm.Left = frm.Left + (e.X - intLeft);
                    frm.Top = frm.Top + (e.Y - intTop);
                    bolBeginDrag = false;
                }
            };
            c.MouseMove += (object s, MouseEventArgs e) =>
            {
                if (bolBeginDrag)
                {
                    frm.Left = frm.Left + (e.X - intLeft);
                    frm.Top = frm.Top + (e.Y - intTop);
                }
            };
            c.MouseLeave += (object s, EventArgs e) =>
            {
                frm.Opacity = 1;
                bolBeginDrag = false;
            };
        }
        #endregion

        #region 移动窗体方法2

        //窗体移动属性
        [DllImport("user32.dll")]
        public static extern bool ReleaseCapture();

        //发送消息
        [DllImport("user32.dll")]
        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

        //属性
        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_MOVE = 0xF010;
        public const int HTCAPTION = 0x0002;
        /// <summary>
        /// 窗体移动事件(使用WindowsAPI),推荐使用此方法
        /// </summary>
        /// <param name="frm"></param>
        /// <param name="c"></param>
        public static void MoveByControl_(this Form frm, Control c)
        {
            c.MouseDown += (object s, MouseEventArgs e) =>
            {
                if (e.Button == MouseButtons.Left)//只有左键才能移动
                {
                    if (e.Y < c.Height)//只有最上面那行才能实现移动
                    {
                        ReleaseCapture();//捕获鼠标
                        //发送消息
                        SendMessage(frm.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
                    }
                }
            };
        }
        #endregion

        /// <summary>
        /// 重置表单控件的值
        /// </summary>
        /// <param name="frm"></param>
        /// <param name="formLoad"></param>
        public static void ResetForm(this Form frm, Action formLoad = null)
        {
            frm.Controls.Clear();
            if (formLoad != null) formLoad();
            typeof(Form).InvokeMember("InitializeComponent", BindingFlags.InvokeMethod, null, frm, null);
            frm.Refresh();
        }

        /// <summary>
        /// 切换最大化和最小化
        /// <para>支持无边框窗体</para>
        /// </summary>
        /// <param name="frm"></param>
        public static void SwitchMaximized(this Form frm)
        {
            if (frm.WindowState == FormWindowState.Normal)
            {
                if (frm.FormBorderStyle == FormBorderStyle.None) frm.MaximumSize = new Size(Screen.PrimaryScreen.WorkingArea.Width, Screen.PrimaryScreen.WorkingArea.Height);
                frm.WindowState = FormWindowState.Maximized;
            }
            else
            {
                frm.WindowState = FormWindowState.Normal;
            }
        }

        #region 外观
        public static void SetBgImage(this Form frm, Image img)
        {
            frm.BackgroundImage = img;
            frm.BackgroundImageLayout = ImageLayout.Stretch;
        }
        #endregion
    }
}
